﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ttlang.semantic;

namespace ttlang.node
{
    //表达式节点，最低的逻辑层次
    public interface Node_Expr : Node
    {
        bool isConst
        {
            get;

        }//该表达式是否能表达为常量
        double CalcValue();//求值
        bool CalcCondition();//求逻辑值
        semantic.TTType tttype
        {
            get;
        }
    }
    public class Node_Expr_Math : Node_Expr
    {
        public Node_Expr left;
        public string token;
        public Node_Expr right;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get
            {
                //l逻辑运算必然是bool值
                if (token == "==" || token == "!=" || token == "<" || token == ">" || token == "<=" || token == ">=")
                    return semantic.SystemModule.typeBool;
                //2其它运算都是左值类型
                return left.tttype;
            }
        }
        public bool isConst
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_MATH;
        public double CalcValue()
        {
            var lv = left.CalcValue();
            var rv = right.CalcValue();

            if (token == "+")
                return lv + rv;
            if (token == "-")
                return lv - rv;
            if (token == "*")
                return lv * rv;
            if (token == "/")
                return lv / rv;

            throw new NotImplementedException();

        }
        public bool CalcCondition()
        {
            var lv = left.CalcValue();
            var rv = right.CalcValue();
            if (token == "==")
            {
                return (int)lv == (int)rv;
            }
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Math:");
            left.Dump(deep + 1);
            Console.WriteLine(space + "    " + token);
            right.Dump(deep + 1);
        }
    }
    public class Node_Expr_Math3Op : Node_Expr
    {
        public Node_Expr condition;
        public Node_Expr vTrue;
        public Node_Expr vFalse;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            private set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_3OP;
        public double CalcValue()
        {
            if (condition.CalcCondition())
                return vTrue.CalcValue();
            else
                return vFalse.CalcValue();
        }
        public bool CalcCondition()
        {
            if (condition.CalcCondition())
                return vTrue.CalcCondition();
            else
                return vFalse.CalcCondition();
        }
        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Math3Op:");
            condition.Dump(deep + 1);
            vTrue.Dump(deep + 1);
            vFalse.Dump(deep + 1);
        }

    }
    public class Node_Expr_TempVar : Node_Expr
    {
        public compiler.TempVarContext id;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get
            {
                return id.type;
            }
        }
        public NodeType type => NodeType.EXPR_TEMPVAR;
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_TempVar:");
            Console.WriteLine(space + "    Node_TempVar=" + id.id);
        }
    }
    public class Node_Expr_Arg : Node_Expr
    {
        public TTArg arg;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get
            {
                return arg.argtype;
            }
        }
        public NodeType type => NodeType.EXPR_ARGVAR;
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Arg:");
            Console.WriteLine(space + "    arg=" + arg.name);
        }
    }


    public class Node_Expr_Number : Node_Expr
    {
        public Node_Expr_Number(semantic.TTType tttype)
        {
            this.tttype = tttype;
        }
        public string srcnumber;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            private set;
        }
        public NodeType type => NodeType.EXPR_NUMBER;
        public NodeType numbertype;
        public int AsInt()
        {
            return int.Parse(srcnumber);
        }
        public double AsFloat()
        {
            return double.Parse(srcnumber);
        }
        public double CalcValue()
        {
            return AsFloat();
        }
        public bool CalcCondition()
        {
            return AsInt() > 0;
        }
        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Number:");
            Console.WriteLine(space + "    srcnumber=" + srcnumber);
        }

    }
    public class Node_Expr_Array : Node_Expr
    {
        public Node_Expr body;
        public Node_Expr[] indeies;
        public Node_Expr_Array(Node_Expr _body, Node_Expr[] _indeies)
        {
            this.body = _body;
            this.indeies = _indeies;

        }
        public bool isConst
        {
            get;
            set;
        }

        public TTType tttype
        {
            get;
            private set;
        }

        public srcinfo srcinfo
        {
            get;
            set;
        }

        public NodeType type => NodeType.EXPR_ARRAY;

        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {

            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Array:");
            body.Dump(deep + 1);
            Console.WriteLine(space + "==indexcount" + indeies.Length);
            for (var i = 0; i < indeies.Length; i++)
                indeies[i].Dump(deep + 1);
        }
    }
    public class Node_Expr_Unary : Node_Expr
    {
        public Node_Expr_Unary(string token, Node_Expr _expr)
        {
            this.expr = _expr;
            this.token = token;
            this.isConst = expr.isConst;
            tttype = this.expr.tttype;
        }
        public string token;
        public Node_Expr expr;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            private set;
        }
        public bool isConst
        {
            get;
            private set;
        }

        public NodeType type => NodeType.EXPR_UNARY;

        public double CalcValue()
        {
            double v = expr.CalcValue();
            if (token == "-")
                return -v;
            throw new Exception("not supported.");
        }
        public bool CalcCondition()
        {
            bool v = expr.CalcCondition();
            if (token == "!")
                return !v;
            throw new Exception("not supported.");
        }
        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Unary:");
            Console.WriteLine(space + "    token=" + token);
        }

    }
    public class Node_Expr_String : Node_Expr
    {
        public Node_Expr_String(semantic.TTType tttype)
        {
            this.tttype = tttype;
        }
        public string value;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            private set;
        }
        public NodeType type => NodeType.EXPR_STRING;

        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Number:");
            Console.WriteLine(space + "    srcnumber=" + value);
        }

    }
    public class Node_Expr_Bool : Node_Expr
    {
        public Node_Expr_Bool(semantic.TTType tttype)
        {
            this.tttype = tttype;
        }
        public string value;

        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            private set;
        }
        public NodeType type => NodeType.BOOL;

        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Bool:");
            Console.WriteLine(space + "    Bool=" + value);
        }

    }
    public class Node_Expr_Method : Node_Expr
    {
        public semantic.TTMethod method;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_METHOD;
        public semantic.TTType tttype
        {
            get
            {
                return method.tttype;
            }
        }
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Method:" + method.name);
        }
    }
    public class Node_Expr_Member : Node_Expr
    {
        public Node_Expr left;
        public semantic.IMember member;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_MEMBER;
        public semantic.TTType tttype
        {
            get
            {
                return member.tttype;
            }
        }
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            left.Dump(deep);
            Console.WriteLine(space + member.name);
        }
    }

    public class Node_Expr_Call : Node_Expr
    {
        public Node_Expr function;//函数表达式可能会复杂
        public List<Node_Expr> args;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get
            {
                return function.tttype;
            }
        }
        public NodeType type => NodeType.EXPR_CALL;
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Call:");
            function.Dump(deep + 1);
            for (var i = 0; i < args?.Count; i++)
            {
                args[i].Dump(deep + 1);
            }
        }
    }
    public class Node_Expr_New : Node_Expr
    {
        public Node_Expr function;//函数表达式可能会复杂
        public List<Node_Expr> args;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_NEW;
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_New:");
            function.Dump(deep + 1);
            for (var i = 0; i < args?.Count; i++)
            {
                args[i].Dump(deep + 1);
            }
        }
    }
    public class Node_Expr_Cast : Node_Expr
    {
        public Node_Expr srcexpr;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public semantic.TTType tttype
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_CAST;
        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Cast:" + tttype.name);
            srcexpr.Dump(deep + 1);
        }
    }
    public class Node_Expr_Container : Node_Expr
    {
        public semantic.IContainer container;
        public srcinfo srcinfo
        {
            get;
            set;
        }
        public bool isConst
        {
            get;
            set;
        }
        public NodeType type => NodeType.EXPR_CONTAINER;
        public semantic.TTType tttype
        {
            get
            {
                return container as semantic.TTType;
            }
        }

        public bool CalcCondition()
        {
            throw new NotImplementedException();
        }

        public double CalcValue()
        {
            throw new NotImplementedException();
        }

        public void Dump(int deep)
        {
            string space = "";
            for (var i = 0; i < deep; i++)
                space += "    ";
            Console.WriteLine(space + "Node_Expr_Container:" + container.name);
        }
    }
}
